using System;
using System.Data;
using System.Collections;

/*
    CssDom Library
    Copyright (C) 2007-2011  Ferenc Veres

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

namespace WPS.Libraries.CssDom
{
	public class CSSStyleDeclaration
	{
		#region Private implementation related, nonstandard properties.

		/// <summary>
		/// Stores the style declaration's property names in original order.
		/// </summary>
		private ArrayList propertyNames;

		/// <summary>
		/// Stores the style declaration's property values in original order.
		/// </summary>
		private ArrayList propertyValues;

		/// <summary>
		/// Stores the style declaration's property's prority (!important) values in original order.
		/// </summary>
		private ArrayList propertyPriorities;

		#endregion

		#region CSSStyleDeclaration interface public properties

		/// <summary>
		/// TODO: NOT IMPLEMENTED [wps 4.4 ok, Lion]
		/// The CSS rule that contains this declaration block or null if this 
		/// CSSStyleDeclaration is not attached to a CSSRule.
		/// </summary>
		public CSSRule parentRule
		{
			get
			{
				throw new Exception("Not implemented yet.");
			}
		}

		/// <summary>
		/// The parsable textual representation of the declaration block 
		/// (excluding the surrounding curly braces).
		/// </summary>
		/// <remarks>
		/// Setting this attribute will result in the parsing of the new value and 
		/// resetting of all the properties in the declaration block including the 
		/// removal or addition of properties.
		/// </remarks>
		public string cssText
		{
			get
			{
				// Concatenate all names/keys/priorities to one declaration string
				string retVal = "";
				for(int i = 0; i < propertyNames.Count; i++)
				{
					retVal += (string)propertyNames[i] + ": " + (string)propertyValues[i];
					if((string)propertyPriorities[i] != "")
					{
						retVal += " " + propertyPriorities[i];
					}
					if(i != propertyNames.Count)
					{
						retVal += ";\n";
					}
				}
				return retVal;
			}
			set
			{
				parseDeclaration(value);
			}
		}

		/// <summary>
		/// The number of properties that have been explicitly set in this declaration block. 
		/// The range of valid indices is 0 to length-1 inclusive.
		/// </summary>
		public int length
		{
			get
			{
				return this.propertyNames.Count;
			}
		}

		#endregion

		#region Initialization

		/// <summary>
		/// Creates a CSS Style Declaration and fills the properties.
		/// </summary>
		/// <param name="declaration">Parsable string of properties in the declaration. 
		/// (Contents of a CSS rule without curly brackets.)</param>
		public CSSStyleDeclaration(string declaration)
		{
			parseDeclaration(declaration);
		}

		#endregion

		#region CSSStyleDeclaration interface: reading accessing properties

		/// <summary>
		/// TODO: NOT IMPLEMENTED. [wps 4.4 ok, Lion]
		/// Used to retrieve the object representation of the value of a CSS property 
		/// if it has been explicitly set within this declaration block.
		/// </summary>
		/// <remarks>
		/// This method returns null if the property is a shorthand property. 
		/// Shorthand property values can only be accessed and modified as strings, 
		/// using the getPropertyValue and setProperty methods.
		/// </remarks>
		/// <param name="propertyName">The name of the CSS property.
		/// See http://www.w3.org/TR/1998/REC-CSS2-19980512/propidx.html</param>
		/// <returns>Returns the value of the property if it has been explicitly set for this declaration block.
		/// Returns null if the property has not been set.</returns>
		public CSSValue getPropertyCSSValue(string propertyName)
		{
			//int index = propertyNames.IndexOf(propertyName);
			throw new NotImplementedException("Not implemented yet");
		}

		/// <summary>
		/// Used to retrieve the priority of a CSS property (e.g. the "important" qualifier) 
		/// if the property has been explicitly set in this declaration block.
		/// </summary>
		/// <param name="propertyName">The name of the CSS property.
		/// See http://www.w3.org/TR/1998/REC-CSS2-19980512/propidx.html</param>
		/// <returns>A string representing the priority (e.g. "important") if one exists. 
		/// The empty string if none exists.</returns>
		public string getPropertyPriority(string propertyName)
		{
			int index = propertyNames.IndexOf(propertyName);
			if(index != -1)
			{
				return (string)this.propertyPriorities[index];
			}
			return "";
		}

		/// <summary>
		/// Used to retrieve the value of a CSS property if it has been explicitly set within this declaration block.
		/// </summary>
		/// <param name="propertyName">The name of the CSS property. 
		/// See http://www.w3.org/TR/1998/REC-CSS2-19980512/propidx.html</param>
		/// <returns>Returns the value of the property if it has been explicitly set for this declaration block.
		/// Returns the empty string if the property has not been set.</returns>
		public string getPropertyValue(string propertyName)
		{
			int index = propertyNames.IndexOf(propertyName);
			if(index != -1)
			{
				return (string)this.propertyValues[index];
			}
			return "";
		}

		/// <summary>
		/// Used to retrieve the properties that have been explicitly set in this declaration block.
		/// </summary>
		/// <remarks>
		/// The order of the properties retrieved using this method does not have 
		/// to be the order in which they were set. This method can be used to iterate 
		/// over all properties in this declaration block.
		/// </remarks>
		/// <param name="index">Zero based index of the property name to retrieve.</param>
		/// <returns>The name of the property at this ordinal position. 
		/// The empty string if no property exists at this position.</returns>
		public string item(int index)
		{
			if(propertyNames.Count > index)
			{
				return (string)propertyNames[index];
			}
			return "";
		}
		#endregion

		#region CSSStyleDeclaration interface: modifying properties

		/// <summary>
		/// Used to remove a CSS property if it has been explicitly set within this declaration block.
		/// </summary>
		/// <param name="propertyName">The name of the CSS property. 
		/// See http://www.w3.org/TR/1998/REC-CSS2-19980512/propidx.html</param>
		/// <returns>Returns the value of the property if it has been explicitly set for this declaration block.
		/// Returns the empty string if the property has not been set or the property name does not 
		/// correspond to a known CSS property.</returns>
		public string removeProperty(string propertyName)
		{
			int index = propertyNames.IndexOf(propertyName);
			if(index != -1)
			{
				string oldValue = (string)this.propertyValues[index];
				this.propertyValues.RemoveAt(index);
				this.propertyNames.RemoveAt(index);
				this.propertyPriorities.RemoveAt(index);
				return oldValue;
			}
			else
			{
				return "";
			}
		}

		/// <summary>
		/// Used to set a property value and priority within this declaration block.
		/// </summary>
		/// <param name="propertyName">The name of the CSS property. 
		/// See http://www.w3.org/TR/1998/REC-CSS2-19980512/propidx.html</param>
		/// <param name="value">The new value of the property.</param>
		/// <param name="proirity">The new priority of the property (e.g. "important").</param>
		public void setProperty(string propertyName, string value, string proirity)
		{
			int index = propertyNames.IndexOf(propertyName);
			if(index != -1)
			{
				this.propertyNames[index] = propertyName.ToLower();
				this.propertyValues[index] = value;
				this.propertyPriorities[index] = proirity;
			}
			else
			{
				this.propertyNames.Add(propertyName.ToLower());
				this.propertyValues.Add(value);
				this.propertyPriorities.Add(proirity);
			}
		}

		#endregion

		#region Implementation related, nonstandard methods

		/// <summary>
		/// Checks if the rule defines the specified property. Non-standard DOM method.
		/// </summary>
		/// <param name="propertyName">Property name to check.</param>
		/// <returns>True if the name is defined (and most likely has a value).</returns>
		public bool defines(string propertyName)
		{
			int index = propertyNames.IndexOf(propertyName);
			return (index != -1);
		}

		/// <summary>
		/// Parse a string containing one css class' contents, set property names and their values in propertyhash.
		/// </summary>
		private void parseDeclaration(string declaration)
		{
			this.propertyNames = new ArrayList();
			this.propertyValues = new ArrayList();
			this.propertyPriorities = new ArrayList();

			string[] nameValues, nameAndValue;
			string name, value;

			nameValues = declaration.Split(';');
			foreach(string nameValue in nameValues)
			{
				nameAndValue = nameValue.Split(':');

				if(nameAndValue.Length == 2)
				{
					name = nameAndValue[0].Trim();
					value = nameAndValue[1].Trim();

					setProperty(name, value, "");
				}
			}
		}
		#endregion

	}
}
